package wsepForum.domain;

import java.util.Date;
import java.util.Vector;

import wsepForum.domain.handlers.AUserHandler;
import wsepForum.domain.handlers.GuestHandler;
import wsepForum.persistance.IPersistentHandler;
import wsepForum.persistance.exceptions.DataBaseIOException;
import wsepForum.ui.console.ConsoleUIState;

/**
* Holds information about a single user connection session
* also holds the right handler that deals with the specific user's requests
* @author Amir Harel & Ariel Rozen & Oren Ben-Haim
*
*/
public class Session {

	/*****************************
	 * MEMBERS                   *
	 *****************************/
	/**
	 * The interface between the GUI layer and the domain layer.
	 */
	private AUserHandler handler;

	/**
	 * Session ID
	 */
	private double sessionID;

	/**
	 * User's connection time
	 */
	private Date connectTime;

	/**
	 * User's login time (to the forum, as a registered user)
	 */
	private Date loginTime = null;

	/**
	 * User's current state in the ui.
	 */
	private ConsoleUIState uiState;

	/**
	 *
	 */
	private Vector<ISessionObserver> observers;

	/*****************************
	 * CONSTRUCTOR               *
	 *****************************/
	/**
	 * Inits a user's session object with a guest handler
	 * @param sid Session ID
	 * @param pers The interface supplied by the persistent layer.
	 */
	public Session(double sid, IPersistentHandler pers) {
		this.observers = new Vector<ISessionObserver>();
		setSessionID(sid);
		// set connect time:
		Date date = new Date();
		date.setTime(System.currentTimeMillis());
		setConnectTime(date);
		// inits User ui state
		this.uiState = new ConsoleUIState();
		// init a guest session
		setHandler(new GuestHandler(pers));
	}


	/*****************************
	 * METHODS                   *
	 *****************************/
	/**
	 * logs the user into the system using a user name and password.
	 * once logged in the user acquires additional actions he can perform
	 * in the system according to his level(using an updated handler).
	 * @param userName - the user name entered by the user
	 * @param password - the password entered by the user.
	 * @return true, if login was successful
	 * @throws Exception on a login's problem
	 */
	public boolean login (String userName, String password) throws Exception {
		if (getHandler()== null)	// user handler is not initiated
			return false;
		try {
			AUserHandler uHandler = handler.login(userName, password);
			SessionManager.getInstance().addUserSession(userName, this);
			// set login time:
			Date date = new Date();
			date.setTime(System.currentTimeMillis());
			setLoginTime(date);
			setHandler(uHandler); // update to new handler
			return true;
		}
		catch (DataBaseIOException ex) {
			return false;
		}
	}

	/**
	 * logs out the user from the system, making him on a guest level again,
	 * until the next login.
	 * @return true, if logout was successful
	 */
	public boolean logout () {
		if (getHandler()== null) // user handler is not initiated
			return false;
		try {
			AUserHandler uHandler = handler.logout(this);
			setLoginTime(null);
			setHandler(uHandler); // update to new handler
			return true;
		}
		catch (Exception ex) {
			return false;
		}
	}

	public void notifyUserChange(){

	}

	/**
	 * @return The interface between the GUI layer and the domain layer.
	 */
	public AUserHandler getHandler() {
		return handler;
	}

	/**
	 * @param userHandler The interface between the GUI layer and the domain layer.
	 */
	private void setHandler(AUserHandler userHandler) {
		this.handler = userHandler;
	}

	/**
	 * @return Session ID
	 */
	public double getSessionID() {
		return sessionID;
	}


	/**
	 * @param sessionID Session ID
	 */
	private void setSessionID(double sessionID) {
		this.sessionID = sessionID;
	}


	/**
	 * @return User's connection time
	 */
	public Date getConnectTime() {
		return connectTime;
	}


	/**
	 * @param connectTime User's connection time
	 */
	private void setConnectTime(Date connectTime) {
		this.connectTime = connectTime;
	}


	/**
	 * @return User's login time (to the forum, as a registered user)
	 */
	public Date getLoginTime() {
		return loginTime;
	}


	/**
	 * @param loginTime User's login time (to the forum, as a registered user)
	 */
	private void setLoginTime(Date loginTime) {
		this.loginTime = loginTime;
	}


	/**
	 * @return User's current state in the ui.
	 */
	public ConsoleUIState getUiState() {
		return uiState;
	}

	synchronized public void addSessionObserver(ISessionObserver observer){
		this.observers.add(observer);
	}

	synchronized public void removeSessionObserver(ISessionObserver observer){
		this.observers.remove(observer);
	}

	synchronized public Vector<ISessionObserver> getSessionObserverVector(){
		return this.observers;
	}

	synchronized public void reportLocalSessionChange(ISessionObserver reportingObserver) {
		for (ISessionObserver observer : this.observers) {
			if (observer != reportingObserver) {
				observer.onLocalChange();
			}
		}
	}

}
